home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / SCSI Samples 1.0 / SCSI Async Sample 06⁄15 ƒ / Src / GetDevicesToTest.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-16  |  10.5 KB  |  378 lines  |  [TEXT/KAHL]

  1. /*                                GetDevicesToTest.c                                */
  2. /*
  3.  * GetDevicesToTest.c
  4.  * Copyright © 93 Apple Computer Inc. All Rights Reserved.
  5.  *
  6.  * Run the dialog until the user has had enough.
  7.  */
  8. #include "SCSIAsyncSample.h"
  9. #include "DialogUtilities.h"
  10. #include "SCSIDefinitions.h"
  11.  
  12.  
  13. void                        SetupDialog(void);
  14. void                        MakeNewInfoRecord(void);
  15. void                        RefreshParamBlock(void);
  16. void                        RefreshDeviceInfo(void);
  17. Boolean                        CheckInfoRecord(void);
  18. void                        SaveInfoRecord(void);
  19. OSErr                        SetupGetSCSIParamBlock(void);
  20. OSErr                        SetupDeviceInquiry(void);
  21. OSErr                        SetupReadCapacity(void);
  22. void                        StoreDeviceString(
  23.         unsigned char            *dst,
  24.         unsigned char            *src,
  25.         short                    srcLength
  26.     );
  27. unsigned long                GetFourBytes(
  28.         unsigned char            *src
  29.     );
  30.  
  31. /*
  32.  * These are state flags that are valid only for the current
  33.  * dialog.
  34.  */
  35. DialogPtr                    gDialog;
  36. InfoPtr                        gCurrentInfoPtr;
  37. #define INFO                (*gCurrentInfoPtr)
  38. short                        gThreadIndex;
  39.  
  40. void
  41. GetDevicesToTest(void)
  42. {
  43.         GrafPtr                            savePort;
  44.         short                            itemHit;
  45.         Boolean                            needNewInfoRecord;
  46.         Boolean                            needToRefreshDeviceInfo;
  47.         Boolean                            needToRefreshParamBlock;
  48.         Boolean                            needToUpdateDialogValues;
  49.         
  50.         GetPort(&savePort);
  51.         gDialog = GetNewDialog(DLOG_Query, NULL, (WindowPtr) -1L);
  52.         SetCheckBox(gDialog, kQueryEnableAsync, FALSE);
  53.         SetCheckBox(gDialog, kQueryEnableDisconnect, FALSE);
  54.         SetDialogValue(gDialog, kQueryTotalRequests, 100);
  55.         /*
  56.          * For my system: prime the device to point to the CD-Rom
  57.          */
  58.         SetDialogValue(gDialog, kQueryHostBus, 1);
  59.         SetDialogValue(gDialog, kQueryTargetID, 3);
  60.         /* */
  61.         ShowWindow(gDialog);
  62.         SetPort(gDialog);
  63.         gThreadIndex = 0;
  64.         needNewInfoRecord = TRUE;
  65.         InitCursor();
  66.         for (;;) {
  67.             if (needNewInfoRecord) {
  68.                 MakeNewInfoRecord();
  69.                 needNewInfoRecord = FALSE;
  70.                 needToRefreshParamBlock = TRUE;
  71.                 needToUpdateDialogValues = TRUE;
  72.             }
  73.             if (needToRefreshParamBlock) {
  74.                 RefreshParamBlock();
  75.                 needToRefreshParamBlock = FALSE;
  76.                 needToRefreshDeviceInfo = (INFO.pb != NULL);
  77.                 needToUpdateDialogValues = TRUE;
  78.             }
  79.             if (needToRefreshDeviceInfo) {
  80.                 RefreshDeviceInfo();
  81.                 needToRefreshDeviceInfo = FALSE;
  82.                 needToUpdateDialogValues = TRUE;
  83.             }
  84.             if (needToUpdateDialogValues) {
  85.                 SetupDialog();
  86.                 needToUpdateDialogValues = FALSE;
  87.             }
  88.             ModalDialog(NumericFilter, &itemHit);
  89.             switch (itemHit) {
  90.             case kQueryTest:
  91.                 if (CheckInfoRecord()) {
  92.                     SaveInfoRecord();
  93.                     needNewInfoRecord = TRUE;
  94.                 }
  95.                 break;
  96.             case kQueryFinished:
  97.                 if (gCurrentInfoPtr != NULL)
  98.                     DisposePtr((Ptr) gCurrentInfoPtr);
  99.                 goto exit;
  100.             case kQueryHostBus:
  101.                 INFO.deviceIdent.bus = GetDialogValue(gDialog, kQueryHostBus);
  102.                 needToRefreshParamBlock = TRUE;
  103.                 break;
  104.             case kQueryTargetID:
  105.                 INFO.deviceIdent.targetID = GetDialogValue(gDialog, kQueryTargetID);
  106.                 needToRefreshDeviceInfo = TRUE;
  107.                 break;
  108.             case kQueryEnableAsync:
  109.                 SelectCheckBox(gDialog, kQueryEnableAsync, &INFO.enableAsync);
  110.                 break;
  111.             case kQueryEnableDisconnect:
  112.                 SelectCheckBox(gDialog, kQueryEnableDisconnect, &INFO.enableDisconnect);
  113.                 break;
  114.             case kQueryRandomSeek:
  115.                 SelectCheckBox(gDialog, kQueryRandomSeek, &INFO.enableRandomSeek);
  116.                 break;
  117.             case kQueryTotalRequests:
  118.                 INFO.totalTransfers = GetDialogValue(gDialog, kQueryTotalRequests);
  119.                 break;
  120.             case kQueryBlocksPerTransfer:
  121.                 INFO.transferSizeBlocks = GetDialogValue(gDialog, kQueryBlocksPerTransfer);
  122.                 break;
  123.             case kQueryTimeout:
  124.                 INFO.completionTimeout = GetDialogValue(gDialog, kQueryTimeout);
  125.             default:
  126.                 break;
  127.             }
  128.         }
  129. exit:    ;
  130.         DisposDialog(gDialog);
  131.         SetPort(savePort);
  132. }
  133.  
  134. /*
  135.  * MakeNewInfoRecord creates a new, empty, InfoRecord and sets state flags
  136.  * so that the first call to SetupDialog fills in the information.
  137.  */
  138. void
  139. MakeNewInfoRecord(void)
  140. {
  141.         Str255                        work;
  142.         
  143.         gCurrentInfoPtr = (InfoPtr) NewPtrClear(sizeof (InfoRecord));
  144.         if (gCurrentInfoPtr == NULL)
  145.             FatalError(MemError(), "\pCan't make new InfoRecord");
  146.         ++gThreadIndex;
  147.         INFO.threadIndex = gThreadIndex;
  148.         INFO.deviceActive = FALSE;
  149.         INFO.testCompleted = FALSE;
  150.         INFO.completionTimeout = (60L * 15L);            /* 15 seconds            */
  151.         /*
  152.          * Copy the current dialog parameters into the new info record.
  153.          */
  154.         INFO.deviceIdent.bus = GetDialogValue(gDialog, kQueryHostBus);
  155.         INFO.deviceIdent.targetID = GetDialogValue(gDialog, kQueryTargetID);
  156.         INFO.totalTransfers = GetDialogValue(gDialog, kQueryTotalRequests);
  157.         INFO.transferSizeBlocks = GetDialogValue(gDialog, kQueryBlocksPerTransfer);
  158.         INFO.completionTimeout = GetDialogValue(gDialog, kQueryTimeout);
  159.         INFO.enableAsync = GetDialogButton(gDialog, kQueryEnableAsync) == kCheckedButton;
  160.         INFO.enableDisconnect = GetDialogButton(gDialog, kQueryEnableDisconnect) == kCheckedButton;
  161.         INFO.enableRandomSeek = GetDialogButton(gDialog, kQueryRandomSeek) == kCheckedButton;
  162.         GetDateTime(&INFO.randomSeed);
  163.         INFO.randomSeed ^= TickCount();
  164.         NumToString(INFO.threadIndex, work);
  165.         pstrcat(work, "\p Thread index");
  166.         SetDialogText(gDialog, kQueryThreadNumber, work);
  167. }
  168.  
  169. /*
  170.  * SetupDialog is executed each time through the dialog loop to enable and
  171.  * disable editable items and to get information about the active device.
  172.  */
  173. void
  174. SetupDialog(void)
  175. {        
  176.         EnableDialogItem(gDialog, kQueryTest, INFO.validDevice);
  177.         EnableDialogItem(gDialog, kQueryTotalRequests, INFO.validDevice);
  178.         EnableDialogItem(gDialog, kQueryBlocksPerTransfer, INFO.validDevice);
  179.         EnableDialogItem(gDialog, kQueryTimeout, INFO.validDevice);
  180.         EnableDialogItem(gDialog, kQueryEnableAsync, INFO.validDevice);
  181.         EnableDialogItem(gDialog, kQueryEnableDisconnect, INFO.validDevice);
  182.         if (INFO.validDevice) {
  183.             SetDialogValue(gDialog, kQueryBlocksPerTransfer, INFO.transferSizeBlocks);
  184.             SetDialogValue(gDialog, kQueryTimeout, INFO.completionTimeout);
  185.             SetDialogText(gDialog, kQueryVendorID, (StringPtr) INFO.vendor);
  186.             SetDialogText(gDialog, kQueryProduct, (StringPtr) INFO.product);
  187.             SetDialogValue(gDialog, kQueryLogicalBlockLength, INFO.logicalBlockLength);
  188.             SetDialogValue(gDialog, kQueryBlocksOnDevice, INFO.totalLogicalBlocks);
  189.         }
  190.         else {
  191.             SetDialogText(gDialog, kQueryBlocksPerTransfer, "\p");
  192.             SetDialogText(gDialog, kQueryTimeout, "\p");
  193.             SetDialogText(gDialog, kQueryVendorID, "\p");
  194.             SetDialogText(gDialog, kQueryProduct, "\p");
  195.             SetDialogText(gDialog, kQueryLogicalBlockLength, "\p");
  196.             SetDialogText(gDialog, kQueryBlocksOnDevice, "\p");
  197.         }
  198. }
  199.  
  200. void
  201. RefreshDeviceInfo(void)
  202. {
  203.         OSErr                status;
  204.         
  205.         if (INFO.pb != NULL) {
  206.             status = SetupDeviceInquiry();
  207.             if (status == noErr)
  208.                 status = SetupReadCapacity();
  209.             INFO.validDevice = (status == noErr);
  210.         }
  211. }
  212.  
  213. /*
  214.  * Return TRUE if the InfoRecord is valid - this allocates the data buffer.
  215.  */
  216. Boolean
  217. CheckInfoRecord(void)
  218. {
  219.         Str15                    work;
  220.         
  221.         if (INFO.validDevice == FALSE)
  222.             return (FALSE);
  223.         else {
  224.             INFO.totalTransfers = GetDialogValue(gDialog, kQueryTotalRequests);
  225.             INFO.transferSizeBlocks = GetDialogValue(gDialog, kQueryBlocksPerTransfer);
  226.             INFO.completionTimeout = GetDialogValue(gDialog, kQueryTimeout);
  227.             INFO.bufferLength = (INFO.transferSizeBlocks * INFO.logicalBlockLength);
  228.             INFO.bufferPtr = NewPtr(INFO.bufferLength);
  229.             if (INFO.bufferPtr == NULL) {
  230.                 NumToString(INFO.bufferLength, work);
  231.                 ParamText(work, "\p", "\p", "\p");
  232.                 StopAlert(ALRT_NoMemory, NULL);
  233.                 return (FALSE);
  234.             }
  235.             /* To do: read one block to verify that everything is in place */
  236.             return (TRUE);
  237.         }
  238. }
  239.  
  240. /*
  241.  * SaveInfoRecord links this InfoRecord into the active queue.
  242.  */
  243. void
  244. SaveInfoRecord(void)
  245. {
  246.         Enqueue((QElemPtr) gCurrentInfoPtr, &infoPtrQueue);
  247.         gCurrentInfoPtr = NULL;        
  248. }
  249.  
  250. /*
  251.  * Get the SCSI 4.3 Exec I/O parameter block. If this succeeds,
  252.  * INFO.pb points to the parameter block, and INFO.pbSize has
  253.  * its length. On failure, INFO.pb is NULL and INFO.pbSize zero.
  254.  */
  255. void
  256. RefreshParamBlock(void)
  257. {
  258.         OSErr                    status;
  259.         SCSIBusInquiryPB        pb;
  260.  
  261.         CLEAR(pb);
  262.         pb.scsiPBLength = sizeof pb;
  263.         pb.scsiFunctionCode = SCSIBusInquiry;
  264.         pb.scsiCompletion = NULL;
  265.         pb.scsiFlags = 0;
  266.         pb.scsiDevice = INFO.deviceIdent;
  267.         SCSIAction((SCSI_PB *) &pb);
  268.         status = pb.scsiResult;
  269.         if (status == noErr) {
  270.             if (INFO.pb != NULL && INFO.pbSize != pb.scsiIOpbSize) {
  271.                 DisposePtr((Ptr) INFO.pb);
  272.                 INFO.pb = NULL;
  273.                 INFO.pbSize = 0;
  274.             }
  275.             if (INFO.pb == NULL) {
  276.                 INFO.pb = (SCSIExecIOPB *) NewPtr(pb.scsiIOpbSize);
  277.                 if (INFO.pb == NULL)
  278.                     status = MemError();
  279.                 else {
  280.                     INFO.pbSize = pb.scsiIOpbSize;
  281.                 }
  282.             }
  283.         }
  284.         if (status != noErr) {
  285.             NonFatalError(status, "\pCan't allocate SCSI Parameter Block");
  286.             if (INFO.pb != NULL) {
  287.                 DisposePtr((Ptr) INFO.pb);
  288.                 INFO.pb = NULL;
  289.                 INFO.pbSize = 0;
  290.             }
  291.         }
  292. }
  293.  
  294. /*
  295.  * Get the Device Inquiry (vendor, product) data. Return error status.
  296.  */
  297. OSErr
  298. SetupDeviceInquiry(void)
  299. {
  300.         OSErr                        status;
  301.         SCSI_Inquiry_Data            inquiryData;
  302.         const SCSI_6_Byte_Command    inquiryCmd = {
  303.             kScsiCmdInquiry, 0, 0, 0, sizeof inquiryData, 0
  304.         };
  305.  
  306.         status = DoSCSISynchronousIO(
  307.                     gCurrentInfoPtr,                    /* -> INFO                */
  308.                     (SCSI_CommandPtr) &inquiryCmd,        /* Command                */
  309.                     scsiDirectionIn,                    /* Reading from device    */
  310.                     (Ptr) &inquiryData,                    /* -> data buffer        */
  311.                     sizeof inquiryData                    /* data buffer size        */
  312.                 );
  313.         if (status == noErr) {
  314.             StoreDeviceString(INFO.vendor, inquiryData.vendor, sizeof inquiryData.vendor);
  315.             StoreDeviceString(INFO.product, inquiryData.product, sizeof inquiryData.product);
  316.         } 
  317.         return (status);
  318. }
  319.  
  320. /*
  321.  * Get the drive capacity (blocks, logical block length) for the device.
  322.  * Return error status.
  323.  */
  324. OSErr
  325. SetupReadCapacity(void)
  326. {
  327.         OSErr                        status;
  328.         SCSI_Capacity_Data            capacityData;
  329.         const SCSI_10_Byte_Command    capacityCmd = {
  330.             kScsiCmdReadCapacity, 0, 0, 0, 0, 0, 0, 0, 0, 0
  331.         };
  332.  
  333.         status = DoSCSISynchronousIO(
  334.                     gCurrentInfoPtr,                    /* -> INFO                */
  335.                     (SCSI_CommandPtr) &capacityCmd,        /* Command                */
  336.                     scsiDirectionIn,                    /* Reading from device    */
  337.                     (Ptr) &capacityData,                /* -> data buffer        */
  338.                     sizeof capacityData                    /* data buffer size        */
  339.                 );
  340.         if (status == noErr) {
  341.             INFO.totalLogicalBlocks = GetFourBytes(&capacityData.lbn4);
  342.             INFO.logicalBlockLength = GetFourBytes(&capacityData.len4);
  343.         } 
  344.         return (status);
  345. }
  346.  
  347. void
  348. StoreDeviceString(
  349.         unsigned char                *dst,
  350.         unsigned char                *src,
  351.         short                        srcLength
  352.     )
  353. {
  354.         short                        i;
  355.  
  356.         for (i = srcLength; i > 0 && src[i - 1] == ' '; --i) 
  357.             ;
  358.         BlockMove(src, &dst[1], i);
  359.         dst[0] = i;
  360. }
  361.  
  362. unsigned long
  363. GetFourBytes(
  364.         unsigned char                *src
  365.     )
  366. {
  367.         register unsigned long        result;
  368.         
  369.         result = src[0] & 0xFF;
  370.         result <<= 8;
  371.         result |= (src[1] & 0xFF);
  372.         result <<= 8;
  373.         result |= (src[2] & 0xFF);
  374.         result <<= 8;
  375.         result |= (src[3] & 0xFF);
  376.         return (result);
  377. }
  378.